This notebook will contain the code needed to execute our data
analysis project and answer the questions we would like to ask of the
Spotify and YouTube data from Kaggle.
Basic exploratory analysis
** The dataset has 20,718 rows and 28 columns. There are some NA
values within the YouTube data which could serve as a limitation.
Similarly, within the YouTube description values, some of the
descriptions have emojis or other characters and symbols that could be
difficult to work with. Another limitation could arise with the values
in the instrumentalness column since they include negative exponents
which could also be difficult to work with for different analysis
calculations. The original source of the data defines the columns well,
otherwise we may make them more complicated. Since the data includes
artists whose music is on Spotify but probably not every artist in the
world, we would not be able to make assumptions about the music industry
as a whole. Another limitation we can notice is that some of the songs
that fall under an artist’s most popular songs are feautres of said
artist on another song. This can be kind of confusing, but we might be
able to work around it using filters once we start more analysis.
However, this data is also helpful for answering our question about how
collaborations affect an artist’s popularity. One code we would need to
make note of is ‘key,’ which denotes pitch notation but we need to find
a way to make it easily apparent what the pitch is rather than just
seeing a number. There could also be issues with repeat songs when songs
are on more than one album, although sometimes it will be the same song
but a slightly different rendition.
##Questions
Question 1: Which attributes, such as danceability, energy,
loudness, etc., tend to have a correlation with the most streamed
songs?
Analysis: After using code to select the variables
we wanted to work with, we found the correlation coefficient for each
song attribute in relation to the number of streams for each song. After
finding the correlation coefficients, we calculated the mean among the
coefficients for each attribute to average it out. After that, we looked
for the maximum value among all the means, and found that danceability
and streams had the highest positive correlation coefficient of about
0.073. There were some previous errors due to some values being NA, but
using the filter for complete cases got rid of them, and the data we did
use was so large that it provided a general idea of which attribute had
the greatest correlation to number of streams.
attribute_correlate_stream <- spotify_youtube %>%
select(danceability, energy, key, loudness, speechiness, acousticness, instrumentalness, liveness, valence, tempo, stream) %>%
filter(complete.cases(.)) %>%
## find the correlation coefficient between each attribute and number of spotify streams
mutate(
dance_cor = cor(danceability, stream),
energy_cor = cor(energy, stream),
key_cor = cor(key, stream),
speech_cor = cor(speechiness, stream),
acoustic_cor = cor(acousticness, stream),
instrumental_cor = cor(instrumentalness, stream),
live_cor = cor(liveness, stream),
valence_cor = cor(valence, stream),
tempo_cor = cor(tempo, stream)
) %>%
## find the mean correlation coefficient for each attribute
summarise(
mean_dance_cor = mean(dance_cor),
mean_energy_cor = mean(energy_cor),
mean_key_cor = mean(key_cor),
mean_speech_cor = mean(speech_cor),
mean_acoustic_cor = mean(acoustic_cor),
mean_instrumental_cor = mean(instrumental_cor),
mean_live_cor = mean(live_cor),
mean_valence_cor = mean(valence_cor),
mean_tempo_cor = mean(tempo_cor)
)
##output the highest value among the mean coefficients
max_value <- apply(attribute_correlate_stream, 1, max)
Question 2: Does higher engagement on YouTube videos lead to
more streams of the song from the video on Spotify? Is there a
relationship that exists between social engagement and
streams?
Analysis: In order to find and map out the
correlation between Youtube video views and Spotify streams, we first
grouped the data by artist and then summarised the data by the sum of
views and sum of streams for each artist. After that, we plotted the
data into a scatter plot with a line of best fit, which shows that there
is a slight positive correlation between number of views on Youtube and
number of streams on Spotify. This means that it can be generally true
that as one value increases, so does the other. While doing this, we
divided the totals by 1,000,000 because the numbers would have been to
large to easily grasp.
##code to find the total number of views and streams (divided by 1,000,000 because numbers were too large to work with)
streams_views <- spotify_youtube %>%
select(artist, track, stream, views) %>%
mutate(difference = abs(stream-views)) %>%
group_by(artist) %>%
summarise(
total_views = sum(views)/1000000,
total_streams = sum(stream)/1000000,
)
##create a scatterplot with line of best fit
streams_views %>%
ggplot(aes(x=total_streams, y=total_views))+
geom_point(size=2)+
theme_minimal()+
geom_smooth(method = "lm")+
labs(
title = "Correlation between an artist's Spotify Streams and Youtube Views",
x = "Number of Streams on Spotify",
y = "Number of Views on Youtube"
)

##what was happening when that wasn't the case, who was successful on spotify and then not youtube
Question 3: How many videos with a high number of streams are
coming from licensed content?
Analysis: Most videos on YouTube with views over 500
million are coming from licensed content. However, we found that there
are some outliers. About 54 videos were unlicensed and 15 channels
posted unlicensed videos that were also classified as the official video
for the track. Some channels say they are official, like Major Lazer
Official, and then they only have unlicensed content on the platform.
There is no one consistent theme or trend between the channels that have
posted unlicensed content, though it seems like some of them are from
countries outside of the U.S. or rappers and DJs. Redbox also posted
unlicensed videos, which is interesting coming from a company even
though it is not as popular anymore. It seems like some channels are
definitely repurposing content from an unverified user, like
WORLDSTARHIPHOP or perhaps other content is remixes or live performances
in the case of DJs. In doing pivot wider, we can filter for licensed and
unlicensed content as well as official videos and view the total number
of views for each sorted by channel.
youtube_high_views <- spotify_youtube %>%
filter(views > 500000000)
youtube_high_views %>%
group_by(artist) %>%
summarise (
count_licensed = n()
) %>%
arrange(desc(count_licensed))
youtube_high_views %>%
filter(licensed == FALSE)
youtube_high_views %>%
group_by(channel, licensed) %>%
summarize(total_views = sum(views)) %>%
pivot_wider(names_from = licensed, values_from = total_views)
`summarise()` has grouped output by 'channel'. You can override using the `.groups` argument.
youtube_high_views %>%
group_by(channel, official_video) %>%
summarize(total_views = sum(views)) %>%
pivot_wider(names_from = official_video, values_from = total_views) %>%
filter(`FALSE` > 0)
`summarise()` has grouped output by 'channel'. You can override using the `.groups` argument.
##how to get totals for licensed and unlicensed? play around with view numbers
##group by licensed column and then used pivot wider, take the values and make total columns for each
Question 4: How do collaborations or features on a song
affect its popularity on Spotify and YouTube? What are the most popular
collaborations?
Analysis: Some artists definitely seem to be more
successful with their songs that have collaborators on the track
compared to songs where they are the sole artist. We were trying to do a
similar analysis to the question above using pivot_wider to compare the
number of streams for songs with a collaborator and without so we could
see which artists would be best to collaborate with if you want your
song to reach the most people. We ran into an error trying to use pivot
wider in the end, so we will definitely need to brainstorm more
solutions that will move us past this dead end before we complete more
analysis. Either way, Post Malone is the only artist who had streams in
the top 10 for both a single song and a collaboration. Mackelmore and
Ryan Lewis were also in the top 10 highest number of streams for their
collaborative songs, but fall behind for single songs. Also, we noticed
a complication with the data when doing an analysis like this to answer
the question because songs will appear twice under the different
artists’ names even though it is the same song. This can be seen
especially with Mackelmore and Ryan Lewis since the song appears under
Mackelmore, Ryan Lewis and Mackelmore and Ryan Lewis. Industry Baby and
Levitating also appear twice, once under each artist’s name, throwing
off the top 10 most streamed collaborative songs.
spotify_youtube %>%
group_by(artist) %>%
filter(str_detect(track, 'feat.')) %>%
arrange(desc(stream))
spotify_youtube %>%
group_by(artist) %>%
filter(!str_detect(track,'feat.')) %>%
arrange(desc(stream))
##I played around with unique words for the descriptions of YouTube
videos but then decided to ditch my efforts because they weren’t really
that relevant to any major newsworthy findings.
unique_words %>%
count(word, sort = TRUE) %>%
top_n(25) %>%
mutate(word = reorder(word, n))
Selecting by n
Question 5: Do singles or songs from full albums get more
streams? What about views on YouTube? Which artists have more success
with singles compared to full albums and vice versa?
Analysis: More well known American artists were in
the top 10 highest views for YouTube videos coming from songs that were
part of a full album. A lot of the singles were also songs that had
collaborations between artists. None of the artists who had the top
number of streams for singles also had the top number of streams for
songs on a full album. Perhaps collaborative songs also perform better
when they are a single rather than featured in an album. The highest
number of streams for a song that came from an album was The Weeknd’s
“Blinding Lights” which had about a billion more streams than Halsey’s
“Closer” which is the top single with the most amount of streams. The
top videos with the highest views for singles and regular album tracks
were also much different than the results from the Spotify streams in
these categories. What this could tell us is that maybe jsut because a
song is popular does not mean the video to go with it will be as well.
There are deeper visual aspects and social trends that may contribute
more to the number of views on YouTube.
youtube_high_views %>%
filter(album_type == "single") %>%
group_by(artist) %>%
arrange(desc(views))
youtube_high_views %>%
filter(album_type == "album") %>%
group_by(artist) %>%
arrange(desc(views))
NA
Our most newsworthy finding So far, we think our
most newsworthy piece of analysis comes from either the licensed and
unlicensed content on YouTube or the analysis of artist collaborations.
We think that once we are able to complete more analysis on artist
collaborations, it would make for a really interesting article about who
to feature on your track if you want your song to amass a lot of streams
on Spotify. From what we have seen, there have not been any articles
with a central focus along the lines of “Here’s who to make songs with
if you want them to take off,” which we think could be an impactful
finding in and around the music community. Also, with the consumption of
video on the rise between TikTok and YouTube, we think it is newsworthy
to question why certain channels have unlicensed content or how their
videos can be official but unlicensed. As we learn more about how to
navigate social media spaces in terms of regulating content and
copyright, perhaps these findings can provide more insight for those who
make social media rules or who work for the social media companies and
are trying to limit unlicensed content.
LS0tCnRpdGxlOiAiRGF0YSBBbmFseXNpcyBQcm9qZWN0IgpuYW1lczogIktpZXJzdGVuIEhhY2tlciBhbmQgU2hlcndpbi1OZXN0b3IgRXNndWVycmEiCmRhdGU6ICI0LTExLTIwMjMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KClRoaXMgbm90ZWJvb2sgd2lsbCBjb250YWluIHRoZSBjb2RlIG5lZWRlZCB0byBleGVjdXRlIG91ciBkYXRhIGFuYWx5c2lzIHByb2plY3QgYW5kIGFuc3dlciB0aGUgcXVlc3Rpb25zIHdlIHdvdWxkIGxpa2UgdG8gYXNrIG9mIHRoZSBTcG90aWZ5IGFuZCBZb3VUdWJlIGRhdGEgZnJvbSBLYWdnbGUuCgpgYGB7ciBzZXR1cCwgaW5jbHVkZT1GQUxTRX0Ka25pdHI6Om9wdHNfY2h1bmskc2V0KGVjaG8gPSBUUlVFKQpgYGAKCiMjIyBMb2FkIHRoZSBsaWJyYXJpZXMKYGBge3J9CmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KGx1YnJpZGF0ZSkKbGlicmFyeShqYW5pdG9yKQpsaWJyYXJ5KHRpZHl0ZXh0KQpsaWJyYXJ5KHJ2ZXN0KQpgYGAKCiMjIyBMb2FkIGFuZCBjbGVhbiBkYXRhCmBgYHtyfQpzcG90aWZ5X3lvdXR1YmUgPC0gcmVhZF9jc3YoImRhdGEvU3BvdGlmeV9Zb3V0dWJlLmNzdiIpICU+JQpjbGVhbl9uYW1lcygpICU+JQpyZW5hbWUobnVtYmVyID0geDEpICU+JQogIHNlbGVjdCgtYyhudW1iZXIpKSAlPiUKbXV0YXRlKGR1cmF0aW9uX3NlY3MgPSBkdXJhdGlvbl9tcy8xMDAwLCBkdXJhdGlvbl9taW5zID0gZHVyYXRpb25fbXMvNjAwMDApCgpnbGltcHNlKHNwb3RpZnlfeW91dHViZSkKYGBgCgojIyMgQmFzaWMgZXhwbG9yYXRvcnkgYW5hbHlzaXMKKiogVGhlIGRhdGFzZXQgaGFzIDIwLDcxOCByb3dzIGFuZCAyOCBjb2x1bW5zLiBUaGVyZSBhcmUgc29tZSBOQSB2YWx1ZXMgd2l0aGluIHRoZSBZb3VUdWJlIGRhdGEgd2hpY2ggY291bGQgc2VydmUgYXMgYSBsaW1pdGF0aW9uLiBTaW1pbGFybHksIHdpdGhpbiB0aGUgWW91VHViZSBkZXNjcmlwdGlvbiB2YWx1ZXMsIHNvbWUgb2YgdGhlIGRlc2NyaXB0aW9ucyBoYXZlIGVtb2ppcyBvciBvdGhlciBjaGFyYWN0ZXJzIGFuZCBzeW1ib2xzIHRoYXQgY291bGQgYmUgZGlmZmljdWx0IHRvIHdvcmsgd2l0aC4gQW5vdGhlciBsaW1pdGF0aW9uIGNvdWxkIGFyaXNlIHdpdGggdGhlIHZhbHVlcyBpbiB0aGUgaW5zdHJ1bWVudGFsbmVzcyBjb2x1bW4gc2luY2UgdGhleSBpbmNsdWRlIG5lZ2F0aXZlIGV4cG9uZW50cyB3aGljaCBjb3VsZCBhbHNvIGJlIGRpZmZpY3VsdCB0byB3b3JrIHdpdGggZm9yIGRpZmZlcmVudCBhbmFseXNpcyBjYWxjdWxhdGlvbnMuIFRoZSBvcmlnaW5hbCBzb3VyY2Ugb2YgdGhlIGRhdGEgZGVmaW5lcyB0aGUgY29sdW1ucyB3ZWxsLCBvdGhlcndpc2Ugd2UgbWF5IG1ha2UgdGhlbSBtb3JlIGNvbXBsaWNhdGVkLiBTaW5jZSB0aGUgZGF0YSBpbmNsdWRlcyBhcnRpc3RzIHdob3NlIG11c2ljIGlzIG9uIFNwb3RpZnkgYnV0IHByb2JhYmx5IG5vdCBldmVyeSBhcnRpc3QgaW4gdGhlIHdvcmxkLCB3ZSB3b3VsZCBub3QgYmUgYWJsZSB0byBtYWtlIGFzc3VtcHRpb25zIGFib3V0IHRoZSBtdXNpYyBpbmR1c3RyeSBhcyBhIHdob2xlLiBBbm90aGVyIGxpbWl0YXRpb24gd2UgY2FuIG5vdGljZSBpcyB0aGF0IHNvbWUgb2YgdGhlIHNvbmdzIHRoYXQgZmFsbCB1bmRlciBhbiBhcnRpc3QncyBtb3N0IHBvcHVsYXIgc29uZ3MgYXJlIGZlYXV0cmVzIG9mIHNhaWQgYXJ0aXN0IG9uIGFub3RoZXIgc29uZy4gVGhpcyBjYW4gYmUga2luZCBvZiBjb25mdXNpbmcsIGJ1dCB3ZSBtaWdodCBiZSBhYmxlIHRvIHdvcmsgYXJvdW5kIGl0IHVzaW5nIGZpbHRlcnMgb25jZSB3ZSBzdGFydCBtb3JlIGFuYWx5c2lzLiBIb3dldmVyLCB0aGlzIGRhdGEgaXMgYWxzbyBoZWxwZnVsIGZvciBhbnN3ZXJpbmcgb3VyIHF1ZXN0aW9uIGFib3V0IGhvdyBjb2xsYWJvcmF0aW9ucyBhZmZlY3QgYW4gYXJ0aXN0J3MgcG9wdWxhcml0eS4gT25lIGNvZGUgd2Ugd291bGQgbmVlZCB0byBtYWtlIG5vdGUgb2YgaXMgJ2tleSwnIHdoaWNoIGRlbm90ZXMgcGl0Y2ggbm90YXRpb24gYnV0IHdlIG5lZWQgdG8gZmluZCBhIHdheSB0byBtYWtlIGl0IGVhc2lseSBhcHBhcmVudCB3aGF0IHRoZSBwaXRjaCBpcyByYXRoZXIgdGhhbiBqdXN0IHNlZWluZyBhIG51bWJlci4gVGhlcmUgY291bGQgYWxzbyBiZSBpc3N1ZXMgd2l0aCByZXBlYXQgc29uZ3Mgd2hlbiBzb25ncyBhcmUgb24gbW9yZSB0aGFuIG9uZSBhbGJ1bSwgYWx0aG91Z2ggc29tZXRpbWVzIGl0IHdpbGwgYmUgdGhlIHNhbWUgc29uZyBidXQgYSBzbGlnaHRseSBkaWZmZXJlbnQgcmVuZGl0aW9uLgoKIyNRdWVzdGlvbnMKCioqUXVlc3Rpb24gMTogV2hpY2ggYXR0cmlidXRlcywgc3VjaCBhcyBkYW5jZWFiaWxpdHksIGVuZXJneSwgbG91ZG5lc3MsIGV0Yy4sIHRlbmQgdG8gaGF2ZSBhIGNvcnJlbGF0aW9uIHdpdGggdGhlIG1vc3Qgc3RyZWFtZWQgc29uZ3M/KioKCioqQW5hbHlzaXMqKjogQWZ0ZXIgdXNpbmcgY29kZSB0byBzZWxlY3QgdGhlIHZhcmlhYmxlcyB3ZSB3YW50ZWQgdG8gd29yayB3aXRoLCB3ZSBmb3VuZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgZm9yIGVhY2ggc29uZyBhdHRyaWJ1dGUgaW4gcmVsYXRpb24gdG8gdGhlIG51bWJlciBvZiBzdHJlYW1zIGZvciBlYWNoIHNvbmcuIEFmdGVyIGZpbmRpbmcgdGhlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50cywgd2UgY2FsY3VsYXRlZCB0aGUgbWVhbiBhbW9uZyB0aGUgY29lZmZpY2llbnRzIGZvciBlYWNoIGF0dHJpYnV0ZSB0byBhdmVyYWdlIGl0IG91dC4gQWZ0ZXIgdGhhdCwgd2UgbG9va2VkIGZvciB0aGUgbWF4aW11bSB2YWx1ZSBhbW9uZyBhbGwgdGhlIG1lYW5zLCBhbmQgZm91bmQgdGhhdCBkYW5jZWFiaWxpdHkgYW5kIHN0cmVhbXMgaGFkIHRoZSBoaWdoZXN0IHBvc2l0aXZlIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IG9mIGFib3V0IDAuMDczLiBUaGVyZSB3ZXJlIHNvbWUgcHJldmlvdXMgZXJyb3JzIGR1ZSB0byBzb21lIHZhbHVlcyBiZWluZyBOQSwgYnV0IHVzaW5nIHRoZSBmaWx0ZXIgZm9yIGNvbXBsZXRlIGNhc2VzIGdvdCByaWQgb2YgdGhlbSwgYW5kIHRoZSBkYXRhIHdlIGRpZCB1c2Ugd2FzIHNvIGxhcmdlIHRoYXQgaXQgcHJvdmlkZWQgYSBnZW5lcmFsIGlkZWEgb2Ygd2hpY2ggYXR0cmlidXRlIGhhZCB0aGUgZ3JlYXRlc3QgY29ycmVsYXRpb24gdG8gbnVtYmVyIG9mIHN0cmVhbXMuCgpgYGB7cn0KYXR0cmlidXRlX2NvcnJlbGF0ZV9zdHJlYW0gPC0gc3BvdGlmeV95b3V0dWJlICU+JSAKICBzZWxlY3QoZGFuY2VhYmlsaXR5LCBlbmVyZ3ksIGtleSwgbG91ZG5lc3MsIHNwZWVjaGluZXNzLCBhY291c3RpY25lc3MsIGluc3RydW1lbnRhbG5lc3MsIGxpdmVuZXNzLCB2YWxlbmNlLCB0ZW1wbywgc3RyZWFtKSAlPiUgCiAgZmlsdGVyKGNvbXBsZXRlLmNhc2VzKC4pKSAlPiUKIyMgZmluZCB0aGUgY29ycmVsYXRpb24gY29lZmZpY2llbnQgYmV0d2VlbiBlYWNoIGF0dHJpYnV0ZSBhbmQgbnVtYmVyIG9mIHNwb3RpZnkgc3RyZWFtcyAKICAgbXV0YXRlKAogICAgZGFuY2VfY29yID0gY29yKGRhbmNlYWJpbGl0eSwgc3RyZWFtKSwKICAgIGVuZXJneV9jb3IgPSBjb3IoZW5lcmd5LCBzdHJlYW0pLAogICAga2V5X2NvciA9IGNvcihrZXksIHN0cmVhbSksCiAgICBzcGVlY2hfY29yID0gY29yKHNwZWVjaGluZXNzLCBzdHJlYW0pLAogICAgYWNvdXN0aWNfY29yID0gY29yKGFjb3VzdGljbmVzcywgc3RyZWFtKSwKICAgIGluc3RydW1lbnRhbF9jb3IgPSBjb3IoaW5zdHJ1bWVudGFsbmVzcywgc3RyZWFtKSwKICAgIGxpdmVfY29yID0gY29yKGxpdmVuZXNzLCBzdHJlYW0pLAogICAgdmFsZW5jZV9jb3IgPSBjb3IodmFsZW5jZSwgc3RyZWFtKSwKICAgIHRlbXBvX2NvciA9IGNvcih0ZW1wbywgc3RyZWFtKQogICkgJT4lIAojIyBmaW5kIHRoZSBtZWFuIGNvcnJlbGF0aW9uIGNvZWZmaWNpZW50IGZvciBlYWNoIGF0dHJpYnV0ZQogIHN1bW1hcmlzZSgKICAgIG1lYW5fZGFuY2VfY29yID0gbWVhbihkYW5jZV9jb3IpLAogICAgbWVhbl9lbmVyZ3lfY29yID0gbWVhbihlbmVyZ3lfY29yKSwKICAgIG1lYW5fa2V5X2NvciA9IG1lYW4oa2V5X2NvciksCiAgICBtZWFuX3NwZWVjaF9jb3IgPSBtZWFuKHNwZWVjaF9jb3IpLAogICAgbWVhbl9hY291c3RpY19jb3IgPSBtZWFuKGFjb3VzdGljX2NvciksCiAgICBtZWFuX2luc3RydW1lbnRhbF9jb3IgPSBtZWFuKGluc3RydW1lbnRhbF9jb3IpLAogICAgbWVhbl9saXZlX2NvciA9IG1lYW4obGl2ZV9jb3IpLAogICAgbWVhbl92YWxlbmNlX2NvciA9IG1lYW4odmFsZW5jZV9jb3IpLAogICAgbWVhbl90ZW1wb19jb3IgPSBtZWFuKHRlbXBvX2NvcikKICApCiMjb3V0cHV0IHRoZSBoaWdoZXN0IHZhbHVlIGFtb25nIHRoZSBtZWFuIGNvZWZmaWNpZW50cwptYXhfdmFsdWUgPC0gYXBwbHkoYXR0cmlidXRlX2NvcnJlbGF0ZV9zdHJlYW0sIDEsIG1heCkKICAKYGBgCgoqKlF1ZXN0aW9uIDI6IERvZXMgaGlnaGVyIGVuZ2FnZW1lbnQgb24gWW91VHViZSB2aWRlb3MgbGVhZCB0byBtb3JlIHN0cmVhbXMgb2YgdGhlIHNvbmcgZnJvbSB0aGUgdmlkZW8gb24gU3BvdGlmeT8gSXMgdGhlcmUgYSByZWxhdGlvbnNoaXAgdGhhdCBleGlzdHMgYmV0d2VlbiBzb2NpYWwgZW5nYWdlbWVudCBhbmQgc3RyZWFtcz8qKgoKKipBbmFseXNpcyoqOiBJbiBvcmRlciB0byBmaW5kIGFuZCBtYXAgb3V0IHRoZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIFlvdXR1YmUgdmlkZW8gdmlld3MgYW5kIFNwb3RpZnkgc3RyZWFtcywgd2UgZmlyc3QgZ3JvdXBlZCB0aGUgZGF0YSBieSBhcnRpc3QgYW5kIHRoZW4gc3VtbWFyaXNlZCB0aGUgZGF0YSBieSB0aGUgc3VtIG9mIHZpZXdzIGFuZCBzdW0gb2Ygc3RyZWFtcyBmb3IgZWFjaCBhcnRpc3QuIEFmdGVyIHRoYXQsIHdlIHBsb3R0ZWQgdGhlIGRhdGEgaW50byBhIHNjYXR0ZXIgcGxvdCB3aXRoIGEgbGluZSBvZiBiZXN0IGZpdCwgd2hpY2ggc2hvd3MgdGhhdCB0aGVyZSBpcyBhIHNsaWdodCBwb3NpdGl2ZSBjb3JyZWxhdGlvbiBiZXR3ZWVuIG51bWJlciBvZiB2aWV3cyBvbiBZb3V0dWJlIGFuZCBudW1iZXIgb2Ygc3RyZWFtcyBvbiBTcG90aWZ5LiBUaGlzIG1lYW5zIHRoYXQgaXQgY2FuIGJlIGdlbmVyYWxseSB0cnVlIHRoYXQgYXMgb25lIHZhbHVlIGluY3JlYXNlcywgc28gZG9lcyB0aGUgb3RoZXIuIFdoaWxlIGRvaW5nIHRoaXMsIHdlIGRpdmlkZWQgdGhlIHRvdGFscyBieSAxLDAwMCwwMDAgYmVjYXVzZSB0aGUgbnVtYmVycyB3b3VsZCBoYXZlIGJlZW4gdG8gbGFyZ2UgdG8gZWFzaWx5IGdyYXNwLiAKCmBgYHtyfQojI2NvZGUgdG8gZmluZCB0aGUgdG90YWwgbnVtYmVyIG9mIHZpZXdzIGFuZCBzdHJlYW1zIChkaXZpZGVkIGJ5IDEsMDAwLDAwMCBiZWNhdXNlIG51bWJlcnMgd2VyZSB0b28gbGFyZ2UgdG8gd29yayB3aXRoKQpzdHJlYW1zX3ZpZXdzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUgCiAgc2VsZWN0KGFydGlzdCwgdHJhY2ssIHN0cmVhbSwgdmlld3MpICU+JSAKICBtdXRhdGUoZGlmZmVyZW5jZSA9IGFicyhzdHJlYW0tdmlld3MpKSAlPiUgCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUgCiAgc3VtbWFyaXNlKAogICAgdG90YWxfdmlld3MgPSBzdW0odmlld3MpLzEwMDAwMDAsCiAgICB0b3RhbF9zdHJlYW1zID0gc3VtKHN0cmVhbSkvMTAwMDAwMCwKICApCiMjY3JlYXRlIGEgc2NhdHRlcnBsb3Qgd2l0aCBsaW5lIG9mIGJlc3QgZml0CnN0cmVhbXNfdmlld3MgJT4lIAogIGdncGxvdChhZXMoeD10b3RhbF9zdHJlYW1zLCB5PXRvdGFsX3ZpZXdzKSkrCiAgZ2VvbV9wb2ludChzaXplPTIpKwogIHRoZW1lX21pbmltYWwoKSsKICBnZW9tX3Ntb290aChtZXRob2QgPSAibG0iKSsKICBsYWJzKAogICAgdGl0bGUgPSAiQ29ycmVsYXRpb24gYmV0d2VlbiBhbiBhcnRpc3QncyBTcG90aWZ5IFN0cmVhbXMgYW5kIFlvdXR1YmUgVmlld3MiLAogICAgeCA9ICJOdW1iZXIgb2YgU3RyZWFtcyBvbiBTcG90aWZ5IiwKICAgIHkgPSAiTnVtYmVyIG9mIFZpZXdzIG9uIFlvdXR1YmUiCiAgKQoKIyNOb3RlcyBmb3IgbW9yZSBpbnZlc3RpZ2F0aW9uCiAgIyN3aGF0IHdhcyBoYXBwZW5pbmcgd2hlbiB0aGF0IHdhc24ndCB0aGUgY2FzZSwgd2hvIHdhcyBzdWNjZXNzZnVsIG9uIHNwb3RpZnkgYW5kIHRoZW4gbm90IHlvdXR1YmUKYGBgCgoqKlF1ZXN0aW9uIDM6IEhvdyBtYW55IHZpZGVvcyB3aXRoIGEgaGlnaCBudW1iZXIgb2Ygc3RyZWFtcyBhcmUgY29taW5nIGZyb20gbGljZW5zZWQgY29udGVudD8qKgoKKipBbmFseXNpcyoqOiBNb3N0IHZpZGVvcyBvbiBZb3VUdWJlIHdpdGggdmlld3Mgb3ZlciA1MDAgbWlsbGlvbiBhcmUgY29taW5nIGZyb20gbGljZW5zZWQgY29udGVudC4gSG93ZXZlciwgd2UgZm91bmQgdGhhdCB0aGVyZSBhcmUgc29tZSBvdXRsaWVycy4gQWJvdXQgNTQgdmlkZW9zIHdlcmUgdW5saWNlbnNlZCBhbmQgMTUgY2hhbm5lbHMgcG9zdGVkIHVubGljZW5zZWQgdmlkZW9zIHRoYXQgd2VyZSBhbHNvIGNsYXNzaWZpZWQgYXMgdGhlIG9mZmljaWFsIHZpZGVvIGZvciB0aGUgdHJhY2suIFNvbWUgY2hhbm5lbHMgc2F5IHRoZXkgYXJlIG9mZmljaWFsLCBsaWtlIE1ham9yIExhemVyIE9mZmljaWFsLCBhbmQgdGhlbiB0aGV5IG9ubHkgaGF2ZSB1bmxpY2Vuc2VkIGNvbnRlbnQgb24gdGhlIHBsYXRmb3JtLiBUaGVyZSBpcyBubyBvbmUgY29uc2lzdGVudCB0aGVtZSBvciB0cmVuZCBiZXR3ZWVuIHRoZSBjaGFubmVscyB0aGF0IGhhdmUgcG9zdGVkIHVubGljZW5zZWQgY29udGVudCwgdGhvdWdoIGl0IHNlZW1zIGxpa2Ugc29tZSBvZiB0aGVtIGFyZSBmcm9tIGNvdW50cmllcyBvdXRzaWRlIG9mIHRoZSBVLlMuIG9yIHJhcHBlcnMgYW5kIERKcy4gUmVkYm94IGFsc28gcG9zdGVkIHVubGljZW5zZWQgdmlkZW9zLCB3aGljaCBpcyBpbnRlcmVzdGluZyBjb21pbmcgZnJvbSBhIGNvbXBhbnkgZXZlbiB0aG91Z2ggaXQgaXMgbm90IGFzIHBvcHVsYXIgYW55bW9yZS4gSXQgc2VlbXMgbGlrZSBzb21lIGNoYW5uZWxzIGFyZSBkZWZpbml0ZWx5IHJlcHVycG9zaW5nIGNvbnRlbnQgZnJvbSBhbiB1bnZlcmlmaWVkIHVzZXIsIGxpa2UgV09STERTVEFSSElQSE9QIG9yIHBlcmhhcHMgb3RoZXIgY29udGVudCBpcyByZW1peGVzIG9yIGxpdmUgcGVyZm9ybWFuY2VzIGluIHRoZSBjYXNlIG9mIERKcy4gSW4gZG9pbmcgcGl2b3Qgd2lkZXIsIHdlIGNhbiBmaWx0ZXIgZm9yIGxpY2Vuc2VkIGFuZCB1bmxpY2Vuc2VkIGNvbnRlbnQgYXMgd2VsbCBhcyBvZmZpY2lhbCB2aWRlb3MgYW5kIHZpZXcgdGhlIHRvdGFsIG51bWJlciBvZiB2aWV3cyBmb3IgZWFjaCBzb3J0ZWQgYnkgY2hhbm5lbC4KCmBgYHtyfQojI2ZpbHRlciB0byBjcmVhdGUgYSBuZXcgZGF0YWZyYW1lIHdpdGggWW91VHViZSB2aWRlb3MgdGhhdCBoYXZlIG92ZXIgNTAwIG1pbGxpb24gdmlld3MKeW91dHViZV9oaWdoX3ZpZXdzIDwtIHNwb3RpZnlfeW91dHViZSAlPiUKICBmaWx0ZXIodmlld3MgPiA1MDAwMDAwMDApCiMjdHJ5aW5nIHRvIGNvdW50IGhvdyBtYW55IGxpY2Vuc2VkIHZpZGVvcyBhcnRpc3RzIGhhdmUKeW91dHViZV9oaWdoX3ZpZXdzICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X2xpY2Vuc2VkID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfbGljZW5zZWQpKQojI2ZpbHRlciBmb3IgdmlkZW9zIHRoYXQgYXJlIG5vdCBsaWNlbnNlZAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZmlsdGVyKGxpY2Vuc2VkID09IEZBTFNFKSAKIyNmaW5kaW5nIHRoZSBhbW91bnQgb2Ygdmlld3MgZm9yIHZpZGVvcyB0aGF0IGFyZSBsaWNlbnNlZCBhbmQgdW5saWNlbnNlZCBhbmQgZ3JvdXBpbmcgaXQgYnkgY2hhbm5lbAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZ3JvdXBfYnkoY2hhbm5lbCwgbGljZW5zZWQpICU+JQogIHN1bW1hcml6ZSh0b3RhbF92aWV3cyA9IHN1bSh2aWV3cykpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gbGljZW5zZWQsIHZhbHVlc19mcm9tID0gdG90YWxfdmlld3MpCiMjZmluZGluZyB0aGUgbnVtYmVyIG9mIHZpZXdzIGZvciB2aWRlb3MgdGhhdCBhcmUgdW5saWNlbnNlZCBidXQgaXQgaXMgdGhlIG9mZmljaWFsIHZpZGVvIGFuZCBncm91cGluZyBpdCBieSBjaGFubmVsIAp5b3V0dWJlX2hpZ2hfdmlld3MgJT4lCiAgZ3JvdXBfYnkoY2hhbm5lbCwgb2ZmaWNpYWxfdmlkZW8pICU+JQogIHN1bW1hcml6ZSh0b3RhbF92aWV3cyA9IHN1bSh2aWV3cykpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gb2ZmaWNpYWxfdmlkZW8sIHZhbHVlc19mcm9tID0gdG90YWxfdmlld3MpICU+JSAKICBmaWx0ZXIoYEZBTFNFYCA+IDApCmBgYAoKKipRdWVzdGlvbiA0OiBIb3cgZG8gY29sbGFib3JhdGlvbnMgb3IgZmVhdHVyZXMgb24gYSBzb25nIGFmZmVjdCBpdHMgcG9wdWxhcml0eSBvbiBTcG90aWZ5IGFuZCBZb3VUdWJlPyBXaGF0IGFyZSB0aGUgbW9zdCBwb3B1bGFyIGNvbGxhYm9yYXRpb25zPyoqCgoqKkFuYWx5c2lzKio6IFNvbWUgYXJ0aXN0cyBkZWZpbml0ZWx5IHNlZW0gdG8gYmUgbW9yZSBzdWNjZXNzZnVsIHdpdGggdGhlaXIgc29uZ3MgdGhhdCBoYXZlIGNvbGxhYm9yYXRvcnMgb24gdGhlIHRyYWNrIGNvbXBhcmVkIHRvIHNvbmdzIHdoZXJlIHRoZXkgYXJlIHRoZSBzb2xlIGFydGlzdC4gV2Ugd2VyZSB0cnlpbmcgdG8gZG8gYSBzaW1pbGFyIGFuYWx5c2lzIHRvIHRoZSBxdWVzdGlvbiBhYm92ZSB1c2luZyBwaXZvdF93aWRlciB0byBjb21wYXJlIHRoZSBudW1iZXIgb2Ygc3RyZWFtcyBmb3Igc29uZ3Mgd2l0aCBhIGNvbGxhYm9yYXRvciBhbmQgd2l0aG91dCBzbyB3ZSBjb3VsZCBzZWUgd2hpY2ggYXJ0aXN0cyB3b3VsZCBiZSBiZXN0IHRvIGNvbGxhYm9yYXRlIHdpdGggaWYgeW91IHdhbnQgeW91ciBzb25nIHRvIHJlYWNoIHRoZSBtb3N0IHBlb3BsZS4gV2UgcmFuIGludG8gYW4gZXJyb3IgdHJ5aW5nIHRvIHVzZSBwaXZvdCB3aWRlciBpbiB0aGUgZW5kLCBzbyB3ZSB3aWxsIGRlZmluaXRlbHkgbmVlZCB0byBicmFpbnN0b3JtIG1vcmUgc29sdXRpb25zIHRoYXQgd2lsbCBtb3ZlIHVzIHBhc3QgdGhpcyBkZWFkIGVuZCBiZWZvcmUgd2UgY29tcGxldGUgbW9yZSBhbmFseXNpcy4gRWl0aGVyIHdheSwgUG9zdCBNYWxvbmUgaXMgdGhlIG9ubHkgYXJ0aXN0IHdobyBoYWQgc3RyZWFtcyBpbiB0aGUgdG9wIDEwIGZvciBib3RoIGEgc2luZ2xlIHNvbmcgYW5kIGEgY29sbGFib3JhdGlvbi4gTWFja2VsbW9yZSBhbmQgUnlhbiBMZXdpcyB3ZXJlIGFsc28gaW4gdGhlIHRvcCAxMCBoaWdoZXN0IG51bWJlciBvZiBzdHJlYW1zIGZvciB0aGVpciBjb2xsYWJvcmF0aXZlIHNvbmdzLCBidXQgZmFsbCBiZWhpbmQgZm9yIHNpbmdsZSBzb25ncy4gQWxzbywgd2Ugbm90aWNlZCBhIGNvbXBsaWNhdGlvbiB3aXRoIHRoZSBkYXRhIHdoZW4gZG9pbmcgYW4gYW5hbHlzaXMgbGlrZSB0aGlzIHRvIGFuc3dlciB0aGUgcXVlc3Rpb24gYmVjYXVzZSBzb25ncyB3aWxsIGFwcGVhciB0d2ljZSB1bmRlciB0aGUgZGlmZmVyZW50IGFydGlzdHMnIG5hbWVzIGV2ZW4gdGhvdWdoIGl0IGlzIHRoZSBzYW1lIHNvbmcuIFRoaXMgY2FuIGJlIHNlZW4gZXNwZWNpYWxseSB3aXRoIE1hY2tlbG1vcmUgYW5kIFJ5YW4gTGV3aXMgc2luY2UgdGhlIHNvbmcgYXBwZWFycyB1bmRlciBNYWNrZWxtb3JlLCBSeWFuIExld2lzIGFuZCBNYWNrZWxtb3JlIGFuZCBSeWFuIExld2lzLiBJbmR1c3RyeSBCYWJ5IGFuZCBMZXZpdGF0aW5nIGFsc28gYXBwZWFyIHR3aWNlLCBvbmNlIHVuZGVyIGVhY2ggYXJ0aXN0J3MgbmFtZSwgdGhyb3dpbmcgb2ZmIHRoZSB0b3AgMTAgbW9zdCBzdHJlYW1lZCBjb2xsYWJvcmF0aXZlIHNvbmdzLgoKYGBge3J9CiMjZmlsdGVyaW5nIHRvIGNyZWF0ZSBhIG5ldyBkYXRhZnJhbWUgdGhhdCBvbmx5IGluY2x1ZGVzIHNvbmdzIHRoYXQgaGF2ZSBvbmUgb3IgbW9yZSBhcnRpc3RzIGZlYXR1cmVkIG9uIHRoZSB0cmFjayBpbmNsdWRpbmcgdGhlIG1haW4gYXJ0aXN0CnNvbmdfZmVhdHVyZXMgPC0gc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihzdHJfZGV0ZWN0KHRyYWNrLCAnZmVhdC4nKSkKCiMjc29ydGluZyB0aHJvdWdoIHRoZSBkYXRhZnJhbWUgdG8gZmluZCB0aGUgYXJ0aXN0IHdobyBoYXMgdGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgd2l0aCBhIGNvbGxhYm9yYXRvciBvbiB0aGVpciB0cmFjawpzb25nX2ZlYXR1cmVzICU+JQogIGdyb3VwX2J5KGFydGlzdCwgc3RyZWFtKSAlPiUKICBhcnJhbmdlKGRlc2Moc3RyZWFtKSkKCnNwb3RpZnlfeW91dHViZSAlPiUKICBncm91cF9ieShhcnRpc3QpICU+JQogIGZpbHRlcihzdHJfZGV0ZWN0KHRyYWNrLCAnZmVhdC4nKSkgJT4lCiAgYXJyYW5nZShkZXNjKHN0cmVhbSkpCiMjZmlsdGVyaW5nIGZvciB0cmFja3Mgd2hlcmUgdGhlcmUgYXJlIG5vIGNvbGxhYm9yYXRvcnMgYW5kIGdyb3VwaW5nIGl0IGJ5IGFydGlzdCBpbiB0aGUgb3JkZXIgb2YgaGlnaGVzdCBzdHJlYW1zIHRvIGxvd2VzdApzcG90aWZ5X3lvdXR1YmUgJT4lCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUKICBmaWx0ZXIoIXN0cl9kZXRlY3QodHJhY2ssJ2ZlYXQuJykpICU+JQogIGFycmFuZ2UoZGVzYyhzdHJlYW0pKQojI2F0dGVtcHRpbmcgdG8gdXNlIHBpdm90X3dpZGVyIHRvIGNvbXBhcmUgdGhlIGFtb3VudCBvZiBzdHJlYW1zIGZvciB0cmFja3Mgd2l0aCBjb2xsYWJvcmF0b3JzIGFuZCB0cmFja3Mgd2l0aG91dC4Kc3BvdGlmeV95b3V0dWJlICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXplKHRvdGFsX3N0cmVhbSA9IHN1bShzdHJlYW0pKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9IHRyYWNrLCB2YWx1ZXNfZnJvbSA9IHRvdGFsX3N0cmVhbSkgJT4lCiAgZmlsdGVyKHN0cl9kZXRlY3QodHJhY2ssJ2ZlYXQuJykpCiAgCiMjTm90ZXMgZm9yIG1vcmUgaW52ZXN0aWdhdGlvbjoKICAjI0hvdyB0byBjb3VudCBob3cgbWFueSBmZWF0dXJlcyBhbiBhcnRpc3QgaGFzLCBpc3N1ZSBvZiByZXBlYXRzIHdoZXJlIHRoZSBzYW1lIHNvbmcgaXMgbGlzdGVkIHVuZGVyIG1vcmUgdGhhbiBvbmUgYXJ0aXN0IChNYWNrZWxtb3JlIGFuZCBSeWFuIExld2lzKQogICMjVHJ5IHRvIHNlZSB3aG8gY29sbGFib3JhdGVycyBhcmUgZm9yIGF0IGxlYXN0IG9uZSBhcnRpc3Qgd2hvIGlzIG1vcmUgc3VjY2Vzc2Z1bCB3aXRoIHNvbWVvbmUgZWxzZSBvbiB0aGVpciB3b3JrCiAgIyNGaW5kIHRoZSBhdmVyYWdlIHZpZXdzIGZvciBhcnRpc3RzIGJ5IHRoZW1zZWx2ZXMgYW5kIHRoZW4gYXJ0aXN0IHZpZXdzIHdpdGggdGhlaXIgY29sbGFib3JhdGl2ZSB3b3JrLCBmaWx0ZXIgZm9yIGZlYXR1cmVkIGFuZCB0aGVuIGZpbHRlciBmb3Igbm90IGZlYXR1cmVkCmBgYAoKIyNJIHBsYXllZCBhcm91bmQgd2l0aCB1bmlxdWUgd29yZHMgZm9yIHRoZSBkZXNjcmlwdGlvbnMgb2YgWW91VHViZSB2aWRlb3MgYnV0IHRoZW4gZGVjaWRlZCB0byBkaXRjaCBteSBlZmZvcnRzIGJlY2F1c2UgdGhleSB3ZXJlbid0IHJlYWxseSB0aGF0IHJlbGV2YW50IHRvIGFueSBtYWpvciBuZXdzd29ydGh5IGZpbmRpbmdzLgoKYGBge3J9CnNwb3RpZnlfeW91dHViZV90ZXh0IDwtIHNwb3RpZnlfeW91dHViZSAlPiUKICBtdXRhdGUodGV4dCA9IGRlc2NyaXB0aW9uKQoKdW5pcXVlX3dvcmRzIDwtIHNwb3RpZnlfeW91dHViZV90ZXh0ICU+JSBzZWxlY3QodGV4dCkgJT4lCiAgdW5uZXN0X3Rva2Vucyh3b3JkLCB0ZXh0KQoKdW5pcXVlX3dvcmRzICU+JQogIGNvdW50KHdvcmQsIHNvcnQgPSBUUlVFKSAlPiUKICB0b3BfbigyNSkgJT4lCiAgbXV0YXRlKHdvcmQgPSByZW9yZGVyKHdvcmQsIG4pKSAKCmBgYAoqKlF1ZXN0aW9uIDU6IERvIHNpbmdsZXMgb3Igc29uZ3MgZnJvbSBmdWxsIGFsYnVtcyBnZXQgbW9yZSBzdHJlYW1zPyBXaGF0IGFib3V0IHZpZXdzIG9uIFlvdVR1YmU/IFdoaWNoIGFydGlzdHMgaGF2ZSBtb3JlIHN1Y2Nlc3Mgd2l0aCBzaW5nbGVzIGNvbXBhcmVkIHRvIGZ1bGwgYWxidW1zIGFuZCB2aWNlIHZlcnNhPyoqCgoqKkFuYWx5c2lzKio6IE1vcmUgd2VsbCBrbm93biBBbWVyaWNhbiBhcnRpc3RzIHdlcmUgaW4gdGhlIHRvcCAxMCBoaWdoZXN0IHZpZXdzIGZvciBZb3VUdWJlIHZpZGVvcyBjb21pbmcgZnJvbSBzb25ncyB0aGF0IHdlcmUgcGFydCBvZiBhIGZ1bGwgYWxidW0uIEEgbG90IG9mIHRoZSBzaW5nbGVzIHdlcmUgYWxzbyBzb25ncyB0aGF0IGhhZCBjb2xsYWJvcmF0aW9ucyBiZXR3ZWVuIGFydGlzdHMuIE5vbmUgb2YgdGhlIGFydGlzdHMgd2hvIGhhZCB0aGUgdG9wIG51bWJlciBvZiBzdHJlYW1zIGZvciBzaW5nbGVzIGFsc28gaGFkIHRoZSB0b3AgbnVtYmVyIG9mIHN0cmVhbXMgZm9yIHNvbmdzIG9uIGEgZnVsbCBhbGJ1bS4gUGVyaGFwcyBjb2xsYWJvcmF0aXZlIHNvbmdzIGFsc28gcGVyZm9ybSBiZXR0ZXIgd2hlbiB0aGV5IGFyZSBhIHNpbmdsZSByYXRoZXIgdGhhbiBmZWF0dXJlZCBpbiBhbiBhbGJ1bS4gVGhlIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgZm9yIGEgc29uZyB0aGF0IGNhbWUgZnJvbSBhbiBhbGJ1bSB3YXMgVGhlIFdlZWtuZCdzICJCbGluZGluZyBMaWdodHMiIHdoaWNoIGhhZCBhYm91dCBhIGJpbGxpb24gbW9yZSBzdHJlYW1zIHRoYW4gSGFsc2V5J3MgIkNsb3NlciIgd2hpY2ggaXMgdGhlIHRvcCBzaW5nbGUgd2l0aCB0aGUgbW9zdCBhbW91bnQgb2Ygc3RyZWFtcy4gVGhlIHRvcCB2aWRlb3Mgd2l0aCB0aGUgaGlnaGVzdCB2aWV3cyBmb3Igc2luZ2xlcyBhbmQgcmVndWxhciBhbGJ1bSB0cmFja3Mgd2VyZSBhbHNvIG11Y2ggZGlmZmVyZW50IHRoYW4gdGhlIHJlc3VsdHMgZnJvbSB0aGUgU3BvdGlmeSBzdHJlYW1zIGluIHRoZXNlIGNhdGVnb3JpZXMuIFdoYXQgdGhpcyBjb3VsZCB0ZWxsIHVzIGlzIHRoYXQgbWF5YmUganN1dCBiZWNhdXNlIGEgc29uZyBpcyBwb3B1bGFyIGRvZXMgbm90IG1lYW4gdGhlIHZpZGVvIHRvIGdvIHdpdGggaXQgd2lsbCBiZSBhcyB3ZWxsLiBUaGVyZSBhcmUgZGVlcGVyIHZpc3VhbCBhc3BlY3RzIGFuZCBzb2NpYWwgdHJlbmRzIHRoYXQgbWF5IGNvbnRyaWJ1dGUgbW9yZSB0byB0aGUgbnVtYmVyIG9mIHZpZXdzIG9uIFlvdVR1YmUuIAoKYGBge3J9CiMjZmlsdGVyaW5nIGZvciBzaW5nbGVzIGFuZCBhcnJhbmdpbmcgdGhlbSBmcm9tIGhpZ2hlc3QgbnVtYmVyIG9mIHN0cmVhbXMgdG8gbG93ZXN0CnNwb3RpZnlfeW91dHViZSAlPiUKICBmaWx0ZXIoYWxidW1fdHlwZSA9PSAic2luZ2xlIikgJT4lCiAgYXJyYW5nZShkZXNjKHN0cmVhbSkpCiMjZmlsdGVyaW5nIGZvciB0cmFja3MgZnJvbSBmdWxsIGFsYnVtcyBhbmQgYXJyYW5naW5nIHRoZW0gZnJvbSBoaWdoZXN0IG51bWJlciBvZiBzdHJlYW1zIHRvIGxvd2VzdCAKc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihhbGJ1bV90eXBlID09ICJhbGJ1bSIpICU+JQogIGFycmFuZ2UoZGVzYyhzdHJlYW0pKSAKIyNjb3VudGluZyB0aGUgbnVtYmVyIG9mIHNpbmdsZXMgYW5kIGZ1bGwgYWxidW0gdHJhY2tzIGVhY2ggYXJ0aXN0IGhhcwpzcG90aWZ5X3lvdXR1YmUgJT4lCiAgZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RyYWNrID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdHJhY2spKQoKc3BvdGlmeV95b3V0dWJlICU+JQogIGZpbHRlcihhbGJ1bV90eXBlID09ICJhbGJ1bSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RyYWNrID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdHJhY2spKQoKIyNjb3VudGluZyB0aGUgbnVtYmVyIG9mIHNpbmdsZSB2aWRlb3MgYW5kIGFsYnVtIHRyYWNrIHZpZGVvcyBhbiBhcnRpc3QgaGFzCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgc3VtbWFyaXNlICgKICAgIGNvdW50X3RpdGxlID0gbigpCiAgKSAlPiUKICBhcnJhbmdlKGRlc2MoY291bnRfdGl0bGUpKQoKeW91dHViZV9oaWdoX3ZpZXdzICU+JQpmaWx0ZXIoYWxidW1fdHlwZSA9PSAiYWxidW0iKSAlPiUKICBncm91cF9ieShhcnRpc3QpICU+JQogIHN1bW1hcmlzZSAoCiAgICBjb3VudF90aXRsZSA9IG4oKQogICkgJT4lCiAgYXJyYW5nZShkZXNjKGNvdW50X3RpdGxlKSkKIyNhcnJhbmdlIHRvIHNlZSB3aGljaCB2aWRlb3MgaGF2ZSB0aGUgaGlnaGVzdCBudW1iZXIgb2Ygdmlld3MgZm9yIHNpbmdsZXMgYW5kIHRyYWNrcyBmcm9tIGFuIGFsYnVtCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gInNpbmdsZSIpICU+JQogIGdyb3VwX2J5KGFydGlzdCkgJT4lCiAgYXJyYW5nZShkZXNjKHZpZXdzKSkKCnlvdXR1YmVfaGlnaF92aWV3cyAlPiUKZmlsdGVyKGFsYnVtX3R5cGUgPT0gImFsYnVtIikgJT4lCiAgZ3JvdXBfYnkoYXJ0aXN0KSAlPiUKICBhcnJhbmdlKGRlc2Modmlld3MpKQoKYGBgCioqT3VyIG1vc3QgbmV3c3dvcnRoeSBmaW5kaW5nKioKU28gZmFyLCB3ZSB0aGluayBvdXIgbW9zdCBuZXdzd29ydGh5IHBpZWNlIG9mIGFuYWx5c2lzIGNvbWVzIGZyb20gZWl0aGVyIHRoZSBsaWNlbnNlZCBhbmQgdW5saWNlbnNlZCBjb250ZW50IG9uIFlvdVR1YmUgb3IgdGhlIGFuYWx5c2lzIG9mIGFydGlzdCBjb2xsYWJvcmF0aW9ucy4gV2UgdGhpbmsgdGhhdCBvbmNlIHdlIGFyZSBhYmxlIHRvIGNvbXBsZXRlIG1vcmUgYW5hbHlzaXMgb24gYXJ0aXN0IGNvbGxhYm9yYXRpb25zLCBpdCB3b3VsZCBtYWtlIGZvciBhIHJlYWxseSBpbnRlcmVzdGluZyBhcnRpY2xlIGFib3V0IHdobyB0byBmZWF0dXJlIG9uIHlvdXIgdHJhY2sgaWYgeW91IHdhbnQgeW91ciBzb25nIHRvIGFtYXNzIGEgbG90IG9mIHN0cmVhbXMgb24gU3BvdGlmeS4gRnJvbSB3aGF0IHdlIGhhdmUgc2VlbiwgdGhlcmUgaGF2ZSBub3QgYmVlbiBhbnkgYXJ0aWNsZXMgd2l0aCBhIGNlbnRyYWwgZm9jdXMgYWxvbmcgdGhlIGxpbmVzIG9mICJIZXJlJ3Mgd2hvIHRvIG1ha2Ugc29uZ3Mgd2l0aCBpZiB5b3Ugd2FudCB0aGVtIHRvIHRha2Ugb2ZmLCIgd2hpY2ggd2UgdGhpbmsgY291bGQgYmUgYW4gaW1wYWN0ZnVsIGZpbmRpbmcgaW4gYW5kIGFyb3VuZCB0aGUgbXVzaWMgY29tbXVuaXR5LiBBbHNvLCB3aXRoIHRoZSBjb25zdW1wdGlvbiBvZiB2aWRlbyBvbiB0aGUgcmlzZSBiZXR3ZWVuIFRpa1RvayBhbmQgWW91VHViZSwgd2UgdGhpbmsgaXQgaXMgbmV3c3dvcnRoeSB0byBxdWVzdGlvbiB3aHkgY2VydGFpbiBjaGFubmVscyBoYXZlIHVubGljZW5zZWQgY29udGVudCBvciBob3cgdGhlaXIgdmlkZW9zIGNhbiBiZSBvZmZpY2lhbCBidXQgdW5saWNlbnNlZC4gQXMgd2UgbGVhcm4gbW9yZSBhYm91dCBob3cgdG8gbmF2aWdhdGUgc29jaWFsIG1lZGlhIHNwYWNlcyBpbiB0ZXJtcyBvZiByZWd1bGF0aW5nIGNvbnRlbnQgYW5kIGNvcHlyaWdodCwgcGVyaGFwcyB0aGVzZSBmaW5kaW5ncyBjYW4gcHJvdmlkZSBtb3JlIGluc2lnaHQgZm9yIHRob3NlIHdobyBtYWtlIHNvY2lhbCBtZWRpYSBydWxlcyBvciB3aG8gd29yayBmb3IgdGhlIHNvY2lhbCBtZWRpYSBjb21wYW5pZXMgYW5kIGFyZSB0cnlpbmcgdG8gbGltaXQgdW5saWNlbnNlZCBjb250ZW50LiAK